package com.zx.mes.oauth.hyl.security.resource;

import com.zx.mes.hyl.utils.PermitAllUrl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;

/**
 * 注解@EnableResourceServer帮我们加入了
 * org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter<br>   --->  OAuth2AuthenticationManager
 * 该filter帮我们从request里解析出access_token<br>
 * 并通过org.springframework.security.oauth2.provider.token.DefaultTokenServices
 * 根据access_token和认证服务器配置里的TokenStore从redis或者jwt里解析出用户
 *
 * @author 华云龙
 * @date 2018-12-17
 */
@Slf4j
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    /**
     * 设置哪些放行的url
     *
     * @param http http
     * @throws Exception 异常
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatcher(new Oauth2RequestedMatcher())
                .authorizeRequests()
                .antMatchers(PermitAllUrl.permitAllUrl("/oauth/token"))
                /// 上述的url全部不需要校验
                .permitAll()
                .anyRequest().authenticated();
    }

    /**
     * 注意只有检测到有token，才会向服务器端发送下面这个请求,否则不会发送,写完后,源码执行要多调几次<br> /// todo
     * o.s.s.oauth2.client.OAuth2RestTemplate   : Created GET request for "http://10.30.90.136:9991/api/long-oauth2-center/user-me"<br>
     * 两种判断
     * 判断来源请求是否包含oauth2授权信息<br>
     * url参数中含有access_token,或者header里有Authorization
     */
    private static class Oauth2RequestedMatcher implements RequestMatcher {
        @Override
        public boolean matches(HttpServletRequest request) {
            // 请求参数中包含access_token参数
            if (request.getParameter(OAuth2AccessToken.ACCESS_TOKEN) != null) {
                log.debug("access_token is true:[{}]",request.getParameter(OAuth2AccessToken.ACCESS_TOKEN));
                return true;
            }

            // 头部的Authorization值以Bearer开头
            String auth = request.getHeader("Authorization");
            log.debug("判断,头部的Authorization值,auth:[{}]",auth);
            if (auth != null) {
                boolean b = auth.startsWith(OAuth2AccessToken.BEARER_TYPE);
                log.debug("判断,头部的Authorization值以Bearer开头:[{}]",b);
                return b;
            }

            return false;
        }
    }
}
